import base64
import copy
import difflib
import re
import urllib

import requests
from django.db.models import Q

from .models import *

proxies = {"http": "http://192.168.0.103:8080"}


# [[{}],{{}}]去重
def ist_dict_duplicate_removal(lists):
    tmplist = []
    for i in lists:
        if i not in tmplist:
            tmplist.append(i)
    return tmplist


# cookie dict变成str
def cookie_conn(cookie):
    c = ""
    for i in cookie:
        for key, value in i.items():
            c = c + key + "=" + value + ";"
    return c


# 将headers变成dict从而用requests的headers
def headers_dict(h):
    headers = {}
    cookies = ""
    for i in h.split("\n"):
        try:
            k = i.split(":")[0].strip()
            v = i.split(":")[1].strip()

            if k == "Cookie":
                cookies = v
            headers[k] = v
        except IndexError:
            pass
    return headers


# 删除没用的cookie内容，优化运行步骤
def delte_cookie(result):
    headers = headers_dict(result.request_headers)
    cookie = result.request_cookies
    availablecookie = []
    if result.method == "GET":
        headers['Cookie'] = cookie
        r = requests.get(url=result.url, headers=headers)
        init_length = len(r.text)
        ck = ""

        for i in cookie.split(";"):
            if len(i) == 0:
                pass
            # elif i + ";" in cookie:
            #    headers['Cookie'] = cookie.replace(i + ";", "").strip()
            else:
                headers['Cookie'] = cookie.replace(i, "").strip()

                r1 = requests.get(url=result.url, headers=headers)
                if len(r1.text) != init_length:
                    ck = ck + i + ";"
                    availablecookie.append(
                        {i.split("=")[0].strip(): urllib.parse.unquote(i.split("=")[1].replace(";", ""))})
    return availablecookie


# 需要优化循环过程
def re_cookie(cookie, ck):
    t = []
    for parms in cookie:
        for key, value in parms.items():
            match = re.search(key + "=" + ".*?;", ck)
            if match == None:
                pass
            else:
                t2 = match.group().replace(";", "").split("=")
                t.append({t2[0]: t2[1]})
    return t


# 判断cookie是否可用
def cookie_status(cklists, results):
    clist = []
    urllist = []
    for cookies in cklists:

        t = results
        for cookie in cookies:
            for key, value in cookie.items():
                ck = key + "=" + value
                t = t.filter(request_cookies__icontains=ck)
        #有可能有cookie和无cookie的长度一样
        for result in results:
            headers = headers_dict(result.request_headers)
            if result.method == "GET":
                r = requests.get(url=result.url, headers=headers)
                init_text = len(r.text)
                headers['Cookie'] = ""
                r1 = requests.get(url=result.url, headers=headers)
                none_text = len(r1.text)

                if init_text != none_text:
                    if cookies not in clist:
                        clist.append(cookies)
                    urllist.append(result.url)
    return clist,set(urllist)


#
def filter_cookie(results):
    k = 0
    cklists = []
    cudict = ""
    for result in results:

        if k == 0:
            cktmp = delte_cookie(result)

            if len(cktmp) == 0:
                pass
            elif cktmp != []:
                k = 1
                cookie = cktmp
                cklists.append(cookie)

        else:
            ck = result.request_cookies
            match_cookie = re_cookie(cookie, ck)
            if match_cookie != []:
                cklists.append(match_cookie)
    if cklists != []:
        cudict = cookie_status(ist_dict_duplicate_removal(cklists), results)

    return cudict


# 解密base64
def isbase64(value):
    # data = "eyduYW1lJzona2trJywnYWdlJzoyMn0"
    missing_padding = 4 - len(value) % 4
    if missing_padding:
        value += '=' * missing_padding
    try:
        result = base64.b64decode(value)
    except:
        return False
    if r"\x" in str(result):
        return False
    else:
        return True


# 只是根据字符串长度大小判断是不是MD5，若要正确判断需要MD5的接口
def ismd5(value):
    if len(value) == 32:
        return True
    else:
        return False
    # api
    # {cmd5,xmd5,somd5 api}


# 判断会话是否已经失效
def session_status(result):
    if result.method == "GET":
        headers = eval(result.request_headers)
        for cookie in eval(result.cookies):
            c = ""
            for i in cookie:
                for key, value in i.items():
                    c = c + key + "=" + value + ";"
            headers['Cookie'] = ""
            r = requests.get(url=result.url, headers=headers)
            r_length = len(r.text)
            headers['Cookie'] = c
            r1 = requests.get(url=result.url, headers=headers)
            r1_length = r1.text
            if r1_length != r_length:
                print(1)
                return True
            else:
                return False
        # r = requests.get(url=result.url,headers = eval(result.request_headers),proxies=proxies)


# 判断参数内容是否是数字
def isnum(value):
    try:
        eval(value)
        int(value)
        return True
    except SyntaxError:
        return False
    except NameError:
        return False


# cookie 越权检测
def cookie_check(result):
    # 从列表中只取一个cookie进行排列组合测试
    cookies = eval(result.cookies)[0]
    headers = eval(result.request_headers)
    ck = cookie_conn(cookies)
    headers['Cookie'] = ck
    if result.method == 'GET':
        r = requests.get(url=result.url, headers=headers)
        init_length = len(r.text)
        for i in cookies:
            for key, value in i.items():
                rl = []
                if isnum(value):
                    for num in range(int(value), int(value) + 10):
                        headers['Cookie'] = ck.replace(key + "=" + value, key + "=" + str(num))
                        r1 = requests.get(url=result.url, headers=headers, )
                        rl.append(len(r1.text))
                elif isbase64(value):
                    pass
                elif ismd5(value):
                    pass
                # 剩下就只有字符串
                else:
                    usernames = ['admin', 'test', 'administrator', '', 'test1', 'test2']
                    for username in usernames:
                        headers['Cookie'] = ck.replace(key + "=" + value, key + "=" + username)
                        r1 = requests.get(url=result.url, headers=headers, )
                        rl.append(len(r1.text))

                rl.append(init_length)
                # if len(set(rl)) == 3:
                #
                #     authresult.objects.get_or_create(raw_id=id, result="参数可能存在越权", parm=key)
                # elif len(set(rl)) > 3:
                #     authresult.objects.get_or_create(raw_id=id, result="参数存在越权", parm=key)
                # else:
                #     authresult.objects.get_or_create(raw_id=id, result="参数不存在越权", parm=key)


    elif result.method == "POST":
        pass


def get_check(result):
    # 三步验证，一，对比有无cookie的长度，判断是普通页面还是业务页面，二，跑参数内容，三，两者cookie对比
    # 1
    cookies = eval(result.cookies)
    headers = eval(result.headers)

    for url in eval(result.getparm):

        temp1 = []


        for cookie in cookies:
            ck = cookie_conn(cookie)
            headers['Cookie'] = ck
            r1 = requests.get(url=url, headers=headers)
            temp1.append(len(r1.text))


    # 2
    #     if len(set(temp1)) == 3:
    #         parms = ""
    #         for i in eval(result.get_parm):
    #             for key, value in i.items():
    #                 parms = parms + key + "=" + value + "&"
    #             host = result.url.split("/")[0] + "//" + result.url.split("/")[2] + "/"
    #             url = host + result.path + "?" + parms
    #             t = 0
    #             for key, value in i.items():
    #                 temp3 = []
    #                 for cookie in cookies:
    #                     ck = cookie_conn(cookie)
    #                     headers['Cookie'] = ck
    #                     temp2 = []
    #
    #                     if isnum(value):
    #                         for num in range(int(value), int(value) + 10):
    #                             url1 = url.replace(key + "=" + value, key + "=" + str(num))
    #                             r2 = requests.get(url=url1, headers=headers)
    #                             temp2.append(len(r2.text))
    #                     elif ismd5(value):
    #                         pass
    #                     elif isbase64(value):
    #                         pass
    #                     else:
    #                         usernames = ['admin', 'test', 'administrator', '', 'test1', 'test2', "asdsacvcxvcxvxcvfdgfdgfd"]
    #                         for username in usernames:
    #                             url1 = url.replace(key + "=" + value, key + "=" + username)
    #                             r2 = requests.get(url=url1, headers=headers, )
    #                             temp2.append(len(r2.text))
    #                     temp3.append(temp2)
    #                 if sorted(temp3[0]) == sorted(temp3[1]):
    #                     print("no vul")
    #                 else:
    #                     print("yes")
    #
    #     else:
    #         print("不需要登陆，也就是没有越权")


def post_check(result):
    pass


# 过滤重复的参数内容，比如id=1，id=2
def filter_dicts(dicts, lists):
    for i in lists:
        # 看到时需不需要只把数字给过滤调
        if dicts.keys() != i.keys():
            return True
        else:
            return False




# 处理数据包，方便越权测试
def filter_raw():
    # 排除40X和50X的数据包，因为这样的数据包，没有越权的意义
    exclude_results = proxy_data.objects.exclude(Q(status_code__icontains="40") | Q(status_code__icontains="50"))
    host_results = exclude_results.values("host").distinct()
    for i in host_results:
        host = i['host']
        temp_results = exclude_results.filter(host=host).values("path", "method").distinct()

        # results = exclude_results.filter(method=temp_results[1]['method'], path=temp_results[1]['path'])
        # filter_cookie(results)
        for t in temp_results:
            # t代表相同path，不同请求方式（GET,POST）
            urllists = []
            results = exclude_results.filter(method=t['method'], path=t['path'])
            headers = headers_dict(results[0].request_headers)
            culist = filter_cookie(results)
            if len(culist) == 0:
                pass
            else:
                rs = authdata.objects.get_or_create(method=t['method'], path=t['path'], host=host)
                if rs[1]:
                    rs[0].headers = headers
                    rs[0].getparm = culist[1]
                    rs[0].cookies = culist[0]
                    rs[0].save()
        #     elif result.method == "POST":
        #         postdata = urllib.parse.unquote(result.request_content)
        #         urllists.append({result.url: postdata})
        #         cklists.append(result.request_cookies)
        #
        # if results[0].method == "GET":
        #
        #     headers = headers_dict(results[0].request_headers)
        #     cs = ist_dict_duplicate_removal(filter_cookie(cklists, headers, results[0]))
        # elif results[0].method == "POST":
        #     headers = headers_dict(results[0].request_headers)
        #     cs = ist_dict_duplicate_removal(filter_cookie(cklists, headers, results[0]))

        # for result in results:
        #     if result.method == "GET":
        #         if len(result.url.split("?")) == 1:
        #             pass
        #         # http://192.168.0.102:7777/captcha.php?200373866 ingore
        #         # 可能存在伪静态越权，不过实际很少，先忽略
        #         elif len(result.url.split("?")) == 2 and "=" in result.url:
        #             pass
        #             #print(result.url)
        # results = rtmp.values("host", "path", "method", "request_content").distinct()

        # for result in results:
        #     if result['method'] == "GET":
        #         rs = rtmp.filter(host=result['host'], path__icontains=result['path'])
        #         ck = []
        #         l = []
        #         for r in rs:
        #             ck.append(r.request_cookies)
        #         request_headers = headers_dict(
        #             rtmp.filter(host=result['host'], path__icontains=result['path'])[0].request_headers)
        #         cookies = filter_cookie(list(set(ck)), request_headers, rs[0])
        #

        #         for r in rs:
        #             dicts = {}
        #             if len(r.url.split("?")) == 1:
        #                 ra = auth_filter_raw.objects.get_or_create(host=result['host'], method=result['method'],
        #                                                            url=r.url.split("?")[0])
        #                 if ra[1]:
        #                     ra[0].request_headers = request_headers
        #                     ra[0].cookies = cookies
        #                     ra[0].save()
        #
        #             # http://192.168.0.102:7777/captcha.php?2124189383 ingore
        #             elif len(r.url.split("?")) > 1 and "=" in r.url:
        #                 for t in r.url.split("?")[1].split("&"):
        #                     elength = len(t.split("="))
        #                     if elength == 2:
        #                         parm = t.split("=")[0]
        #                         content = t.split("=")[1]
        #                         dicts[parm] = content
        #                     # base64
        #                     elif elength > 2:
        #                         parm = t.split("=")[0]
        #                         content = t.split("=")[1] + "=" * (elength - 2)
        #                         dicts[parm] = content
        #
        #                 if {} in l:
        #                     pass
        #                 elif len(l) == 0:
        #                     l.append(dicts)
        #                 elif filter_dicts(dicts, l):
        #                     l.append(dicts)
        #
        #                 url = rtmp.filter(host=result['host'], path__icontains=result['path'])[0].url
        #
        #                 ra = auth_filter_raw.objects.get_or_create(host=result['host'], method=result['method'],
        #                                                            path=result['path'])
        #
        #                 if ra[1]:
        #                     ra[0].request_headers = request_headers
        #                     ra[0].cookies = cookies
        #                     ra[0].get_parm = l
        #                     ra[0].url = url
        #                     ra[0].save()
        # elif result['method'] == "POST":
        #     ck = []
        #     l = []
        #     data = []
        #     rs = rtmp.filter(host=result['host'], path__icontains=result['path'])
        #     for r in rs:
        #         ck.append(r.request_cookies)
        #         l.append(r.url)
        #         data.append({r.url.split("/")[-1]:r.request_content})
        #     cookies = list(set(ck))
        #     urls = list(set(l))
        #
        #     r = auth_filter_raw.objects.get_or_create(host=result['host'], method=result['method'], path=result['path'])
        #     if r[1]:
        #         r[0].request_headers = result['request_headers']
        #         r[0].cookies = cookies
        #         r[0].urls = urls
        #         r[0].datas = data
        #         r[0].save()

        # 执行越权测试


def run_auth():
    results = authdata.objects.all()
    for result in results:
        if result.method == "GET":
            get_check(result)


# xuyaoyouhua
def get_through_num(id, url, headers, cookies, method, key, value, level=1):
    for i in range(0, 10):
        headers['Cookie'] = cookies.replace(key + "=" + value, key + "=" + str(int(value) + i))
        r = requests.get(url=url, headers=headers)
        h = ""
        for (k, v) in headers.items():
            h = h + k + ":" + v + "\n"
        request_raw = method + " " + url + " HTTP/1.1 \n" + h
        if i == 0:
            authdata.objects.get_or_create(raw_id=id, request_raw=request_raw, response_content=r.text,
                                           length=len(r.text), leixing="init", parm=key)
            headers['Cookie'] = cookies.replace(key + "=" + str(int(value) + i), "")
            r = requests.get(url=url, headers=headers)
            h = ""
            for (k, v) in headers.items():
                h = h + k + ":" + v + "\n"
            request_raw = method + " " + url + " HTTP/1.1 \n" + h
            authdata.objects.get_or_create(raw_id=id, request_raw=request_raw, response_content=r.text,
                                           length=len(r.text), leixing="error", parm=key)

        else:
            authdata.objects.get_or_create(raw_id=id, request_raw=request_raw, response_content=r.text,
                                           length=len(r.text), leixing="test", parm=key)

    results = authdata.objects.filter(raw_id=id, parm=key)
    tup = ()
    for result in results:
        tup1 = (result.length,)
        tup = tup + tup1
    num = set(tup)
    if len(num) == 3:
        authresult.objects.get_or_create(raw_id=id, result="参数可能存在越权", parm=key)
    elif len(num) > 3:
        authresult.objects.get_or_create(raw_id=id, result="参数存在越权", parm=key)
    else:
        authresult.objects.get_or_create(raw_id=id, result="参数不存在越权", parm=key)


def get_through_string(id, url, headers, cookies, method, key, value):
    headers['Cookie'] = cookies
    r = requests.get(url=url, headers=headers)
    h = ""
    for (k, v) in headers.items():
        h = h + k + ":" + v + "\n"
    request_raw = method + " " + url + " HTTP/1.1 \n" + h
    authdata.objects.get_or_create(raw_id=id, request_raw=request_raw, response_content=r.text,
                                   length=len(r.text), leixing="init", parm=key)
    headers['Cookie'] = cookies.replace(key + "=" + value + ";", "")
    r = requests.get(url=url, headers=headers)
    h = ""
    for (k, v) in headers.items():
        h = h + k + ":" + v + "\n"
    request_raw = method + " " + url + " HTTP/1.1 \n" + h
    authdata.objects.get_or_create(raw_id=id, request_raw=request_raw, response_content=r.text,
                                   length=len(r.text), leixing="error", parm=key)

    if len(value) == 32:
        authresult.objects.get_or_create(raw_id=id, result="md5", parm=key)
    elif isbase64(value):
        authresult.objects.get_or_create(raw_id=id, result="base64", parm=key)
    elif "session" in key.lower():
        authresult.objects.get_or_create(raw_id=id, result="session忽略", parm=key)
    else:
        userlist = ['admin', "test", "user"]
        for i in userlist:
            headers['Cookie'] = cookies.replace(key + "=" + value, key + "=" + i)
            r = requests.get(url=url, headers=headers)
            h = ""
            for (k, v) in headers.items():
                h = h + k + ":" + v + "\n"
            request_raw = method + " " + url + " HTTP/1.1 \n" + h
            authdata.objects.get_or_create(raw_id=id, request_raw=request_raw, response_content=r.text,
                                           length=len(r.text), leixing="test", parm=key)

        results = authdata.objects.filter(raw_id=id, parm=key)
        tup = ()
        for result in results:
            tup1 = (result.length,)
            tup = tup + tup1
        num = set(tup)
        if len(num) == 3:
            authresult.objects.get_or_create(raw_id=id, result="参数可能存在越权", parm=key)
        elif len(num) > 3:
            authresult.objects.get_or_create(raw_id=id, result="参数存在越权", parm=key)
        else:
            authresult.objects.get_or_create(raw_id=id, result="参数不存在越权", parm=key)


# 判断这个数字是否有用
def get_int_status(url, headers, parm):
    # qing qiu yuan shi
    lengthlist = []
    r = requests.get(url=url, headers=headers)
    lengthlist.append(len(r.text))

    # shezhi canshu wei none
    r1 = requests.get(url=url.replace(parm, parm.split("=")[0] + "="), headers=headers)
    lengthlist.append(len(r1.text))

    for num in range(int(parm.split("=")[1]) + 1, int(parm.split("=")[1]) + 10):
        r = requests.get(url=url.replace(parm, parm.split("=")[0] + "=" + str(num)), headers=headers)
        lengthlist.append(len(r.text))
    if len(set(lengthlist)) == 1:
        print("no ")


# person use
def person_auth(cookieA, cookieB):
    # results = proxy_data.objects.exclude(Q(status_code__icontains="40") | Q(status_code__icontains="50"))
    results = auth_filter_raw.objects.all()
    for result in results:
        if result.method == 'GET':
            id = result.id
            h = result.request_headers
            headers = {}
            cookies = ""
            for i in h.split("\n"):
                try:
                    k = i.split(":")[0].strip()
                    v = i.split(":")[1].strip()

                    if k == "Cookie":
                        cookies = v
                    headers[k] = v
                except IndexError:
                    pass
            url = result.url
            # http://192.168.1.105:7777/owasp-esapi-php/lib/simpletest/test/acceptance_test.php
            # 直接只有页面，没有参数，适合cookie越权
            if len(result.url.split('?')) == 1:

                r = requests.get(url=url, headers=headers)
                init_length = len(r.text)
                ck = ""
                availablecookie = []
                for i in cookies.split(";"):
                    if len(i) == 0:
                        pass
                    elif i + ";" in cookies:
                        headers['Cookie'] = cookies.replace(i + ";", "").strip()
                    else:
                        headers['Cookie'] = cookies.replace(i, "").strip()
                    r1 = requests.get(url=url, headers=headers)

                    # 处理无用的cookie,
                    if len(i) == 0:
                        pass
                    elif len(r1.text) != init_length:
                        ck = ck + i + ";"
                        availablecookie.append({i.split("=")[0].strip(): i.split("=")[1].replace(";", "")})
                # pan duan leixing
                ck = ""
                for i in availablecookie:
                    for (key, value) in i.items():
                        ck = key + "=" + value + ";" + ck
                for i in availablecookie:
                    for (key, value) in i.items():
                        # shuxue
                        if value.isdigit() == True:
                            get_through_num(id, url, copy.deepcopy(headers), ck, result.method, key, value)
                        else:
                            get_through_string(id, url, copy.deepcopy(headers), ck, result.method, key, value)

            else:
                h = result.request_headers
                headers = {}
                cookies = ""
                for i in h.split("\n"):
                    try:
                        k = i.split(":")[0].strip()
                        v = i.split(":")[1].strip()

                        if k == "Cookie":
                            cookies = v
                        headers[k] = v
                    except IndexError:
                        pass
                url = result.url
                for parm in url.split("?")[1].split("&"):
                    if parm.split("=")[1].isdigit() == True:
                        get_int_status(url, headers, parm)
                        #

# company use
